/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.coreGenerator.base.entitygen.enrichedassoudt;

import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.item.ClassGeneratorContext;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.property.ClassPropertyGenerator;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.gencommon.MediateType;
import com.inspur.edp.cef.generator.common.MediatePropertyInfo;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.EntityDataImplGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.EntityGeneratorContext;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.AssoUdtPropGenerator;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.BaseTypePropGenerator;
import com.inspur.edp.cef.generator.entityGenerator.base.dataTypeData.dataTypePropGen.assoUdt.AssoUdtEnrichedInfoGenerator;
import com.inspur.edp.cef.generator.overall.Utils;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

//
//     public class BEUserUdt : IBEUserUdt
//     {
//         public BEUserUdt(IUserUdt userUdt) =>
//             Info = new BEUserInfo(userUdt?.Info);
//
//         public BEUserInfo Info { get; set; }
//
//         UserInfo IUserUdt.Info
//         {
//             get => Info;
//             set
//             {
//                 if (value == null)
//                     Info = null;
//                 if (value is BEUserInfo)
//                     Info = (BEUserInfo)value;
//                 else
//                     Info = new BEUserInfo(value);
//             }
//         }
//
//         getvalue();
//         copyself();
//         .....
//     }
//
public class EnrichedAssoUdtGenerator extends EntityDataImplGenerator {

  private final String parentName;
  protected String nodeCode;
  protected MediateType enrichedType;
  private MediatePropertyInfo propInfo;
  private List<MediatePropertyInfo> udtGetMethods = new ArrayList<MediatePropertyInfo>();

  public EnrichedAssoUdtGenerator(EntityGeneratorContext parentContext, String nodeCode,
      MediateType enrichedType, MediatePropertyInfo propInfo, String parentName) {
    super(parentContext, propInfo.getElement().getID(), propInfo.getMediateType());
    this.nodeCode = nodeCode;
    this.enrichedType = enrichedType;
    this.propInfo = propInfo;
    this.parentName = parentName;
    Add2Context();
  }

  protected final SimpleDataTypeDef getudtType() {
    return ParentContext.getProjContext().getCefGenContext().getMetadataContent(
        propInfo.getElement().getUdtPkgName(), propInfo.getElement().getUdtID());
  }

  private void Add2Context() {
    java.util.HashMap<String, MediateType> nodeAssoTypes = ParentContext
        .getEnrichedUdtAssoTypes().get(nodeCode);
    if (nodeAssoTypes == null) {
      ParentContext.getEnrichedUdtAssoTypes()
          .put(nodeCode, nodeAssoTypes = new java.util.HashMap<String, MediateType>());
    }
    nodeAssoTypes.put(propInfo.getElement().getLabelID(), new MediateType(null, getName()));
  }

  @Override
  protected void beforeInitialize() {
    super.beforeInitialize();
//    for (MediatePropertyInfo info : PropertyInfos.stream().collect(Collectors.toList())) {
//      if (info.getPropertyName().equals(propInfo.getElement().getLabelID())) {
//        continue;
//      }
//      PropertyInfos.remove(info);
//    }
    PropertyInfos.clear();

    IGspCommonField copyElement = propInfo.getElement().clone(propInfo.getElement().getBelongObject(), null);
    copyElement.setIsUdt(false);
    PropertyInfos.add(new MediatePropertyInfo(propInfo.getElement().getLabelID()){{
      setElement(copyElement);
      setPropertyType(AssoUdtEnrichedInfoGenerator.getItemTypeInfo(propInfo.getElement()));
    }});

    IGspCommonField udtField = getudtType().getContainElements().get(0);
    PropertyInfos.add(new MediatePropertyInfo(udtField){{
      setPropertyType(AssoUdtEnrichedInfoGenerator.getItemTypeInfo(udtField));
    }});
  }

  @Override
  protected ClassGeneratorContext createClassInfoContext() {
    return new ClassGeneratorContext();
  }

  @Override
  public String getName() {
    return parentName + propInfo.getElement().getLabelID();
  }

  //protected final override BaseTypePropGenerator GetBaseTypePropGenerator(CefPropertyInfo propertyInfo)
  //{
  //    if (propertyInfo.DeclaringType == udtType)
  //        return new OrgAssoUdtPropGenerator(enrichedType, propertyInfo);
  //    return base.GetBaseTypePropGenerator( propertyInfo);
  //}

  @Override
  protected ArrayList<ClassMethodGenerator> createConstructorGenerators() {
    return new ArrayList<ClassMethodGenerator>(Arrays.asList(
        new EnrichedAssoUdtCtorGenerator(getudtType(), propInfo, getName())));
  }

  @Override
  protected EntityDataImplGenerator getDataChildsGenerator(EntityGeneratorContext parContext,
      IGspCommonObject node) {
    throw new UnsupportedOperationException();
  }

  @Override
  protected List<BaseTypePropGenerator> getBaseTypePropGenerators(
      MediatePropertyInfo propertyInfo) {
    if(propertyInfo.getElement().getLabelID().equals(getudtType().getContainElements().get(0).getLabelID())){
      List<BaseTypePropGenerator> baseTypePropGenerators = new ArrayList<>();
      if(Character.isLowerCase(getudtType().getContainElements().get(0).getLabelID().charAt(0))){
        baseTypePropGenerators.add(new OrgAssoUdtPropGenerator(ParentContext, this.propInfo, true));
      }
      baseTypePropGenerators.add(new OrgAssoUdtPropGenerator(ParentContext, this.propInfo));
      return baseTypePropGenerators;
    }
    return super.getBaseTypePropGenerators(propertyInfo);
  }

  @Override
  protected void addExtendPropertyGenerator(ArrayList<ClassPropertyGenerator> proGenerators) {
    super.addExtendPropertyGenerator(proGenerators);
    //proGenerators.add(new OrgAssoUdtPropGenerator(ParentContext, propInfo));

    IGspCommonField udtField = getudtType().getContainElements().get(0);
    GspAssociation udtAsso = udtField.getChildAssociations().get(0);
    boolean contailId = false;
    for (IGspCommonField refField : udtAsso.getRefElementCollection()) {
      if(refField.getLabelID().equals(udtField.getLabelID().concat("_ID")))
        contailId = true;
      MediatePropertyInfo refPropertyInfo = new MediatePropertyInfo(refField) {{
        setPropertyType(Utils.getRefElementPropertyName(refField, udtAsso,
            ParentContext.getProjContext().getCefGenContext()));
      }};
      proGenerators.add(new AssoUdtPropGenerator(ParentContext, refPropertyInfo,
          udtField.getLabelID()));
    }
    if(!contailId){
      MediatePropertyInfo idPropertyInfo = new MediatePropertyInfo(
              udtField.getLabelID().concat("_ID")) {{
        setElement(udtField);
        setExtendInfo("AssoUdtAtrribute", propInfo.getElement().getLabelID());
        setPropertyType(new TypeInfo(String.class));
      }};
      proGenerators.add(new AssoUdtPropGenerator(ParentContext, idPropertyInfo,
              udtField.getLabelID()));
    }
    GspAssociation currentAsso = propInfo.getElement().getChildAssociations().get(0);
    for(IGspCommonField refField : currentAsso.getRefElementCollection()){
      if(refField.getIsFromAssoUdt()){
        continue;
      }
      MediatePropertyInfo refPropertyInfo = new MediatePropertyInfo(refField) {{
        setPropertyType(Utils.getRefElementPropertyName(refField, currentAsso,
            ParentContext.getProjContext().getCefGenContext()));
      }};
      proGenerators.add(new AssoUdtPropGenerator(ParentContext, refPropertyInfo,
          propInfo.getElement().getLabelID()));
    }
//    if(Character.isLowerCase(udtField.getLabelID().charAt(0))){
//      proGenerators.add(new EnrichedGetSetValueGenerator(udtField, true));
//    }
//    else {
      proGenerators.add(new EnrichedGetSetValueGenerator(udtField));
//    }
  }

  @Override
  protected boolean isValueObject() {
    return true;
  }
}
